package ch.janotta.slawo.ultraquest.items;

import ch.janotta.slawo.ultraquest.rulesets.areas.AreaRuleset;
import ch.janotta.slawo.ultraquest.rulesets.areas.AreaRulesetsFactory;
import ch.janotta.slawo.ultraquest.types.Area;
import ch.janotta.slawo.ultraquest.types.AreaDifficulty;
import ch.janotta.slawo.ultraquest.types.Item;
import ch.janotta.slawo.ultraquest.types.ItemQuality;
import ch.janotta.slawo.ultraquest.utilities.Dice;

public final class ItemFactory {
  /*
   * The algorithm has the following base probabilities:
   * AreaType        EASY         STANDARD    CHALLANGING DIFFICULT   DANGEROUS   DEADLY
   * OVERLAND        90,99        80,99       75,95       60,90       55,85       50,75
   * DUNGEON         80,95        70,90       65,85       50,80       45,75       25,75
   */
  private static final int[][] OVERLAND_PROBABILITIES = new int[][] {
    {90, 99}, {80, 99}, {75, 99}, {60, 90}, {55, 85}, {50, 75}
  };
  private static final int[][] DUNGEON_PROBABILITIES = new int[][] {
    {80, 95}, {70, 90}, {65, 85}, {50, 80}, {45, 75}, {25, 75}
  };

  public static Item getRandomItem(Area area) {
    int itemType = Dice.getRandomNumber(3);
    if (itemType == 1) {
      return getRandomArmor(area);
    } else if (itemType == 2) {
      return getRandomCloseCombatWeapon(area);
    } else {
      return getRandomRangedWeapon(area);
    }
  }

  public static Item getRandomRangedWeapon(Area area) {
    Item item = getBaseRandomItem(area);
    item.setName(item.getQuality().getName() + " bow");
    item.setRangedCombatValue(item.getQuality().getValue());
    return item;
  }

  public static Item getRandomCloseCombatWeapon(Area area) {
    Item item = getBaseRandomItem(area);
    item.setName(item.getQuality().getName() + " sword");
    item.setCloseCombatValue(item.getQuality().getValue());
    return item;
  }

  public static Item getRandomArmor(Area area) {
    Item item = getBaseRandomItem(area);
    item.setName(item.getQuality().getName() + " armor");
    item.setArmorValue(item.getQuality().getValue());
    return item;
  }

  private static Item getBaseRandomItem(Area area) {
    AreaRuleset ruleset = AreaRulesetsFactory.getRulesetInstance(area);
    Item randomItem = new Item();
    randomItem.setQuality(getRandomQuality(ruleset.getDifficulty(), ruleset.getDungeonSetting()));
    return randomItem;
  }

  private static ItemQuality getRandomQuality(AreaDifficulty difficulty, boolean isDungeon) {
    ItemQuality quality = ItemQuality.COMMON;

    int percentage = Dice.getRandomNumber(100);
    if (!isDungeon) {
      switch (difficulty) {
        case EASY:
          quality = getQuality(percentage, OVERLAND_PROBABILITIES[0]);
          break;
        case STANDARD:
          quality = getQuality(percentage, OVERLAND_PROBABILITIES[1]);
          break;
        case CHALLENGING:
          quality = getQuality(percentage, OVERLAND_PROBABILITIES[2]);
          break;
        case DIFFICULT:
          quality = getQuality(percentage, OVERLAND_PROBABILITIES[3]);
          break;
        case DANGEROUS:
          quality = getQuality(percentage, OVERLAND_PROBABILITIES[4]);
          break;
        case DEADLY:
          quality = getQuality(percentage, OVERLAND_PROBABILITIES[5]);
          break;
        default:
          quality = ItemQuality.MASTER;
      }
    } else {
      switch (difficulty) {
        case EASY:
          quality = getQuality(percentage, DUNGEON_PROBABILITIES[0]);
          break;
        case STANDARD:
          quality = getQuality(percentage, DUNGEON_PROBABILITIES[1]);
          break;
        case CHALLENGING:
          quality = getQuality(percentage, DUNGEON_PROBABILITIES[2]);
          break;
        case DIFFICULT:
          quality = getQuality(percentage, DUNGEON_PROBABILITIES[3]);
          break;
        case DANGEROUS:
          quality = getQuality(percentage, DUNGEON_PROBABILITIES[4]);
          break;
        case DEADLY:
          quality = getQuality(percentage, DUNGEON_PROBABILITIES[5]);
          break;
        default:
          quality = ItemQuality.MASTER;
      }
    }

    return quality;
  }

  private static ItemQuality getQuality(int percentage, int[] probabilities) {
    if (percentage <= probabilities[0]) return ItemQuality.COMMON;
    if (percentage <= probabilities[1]) return ItemQuality.EXCELENT;
    return ItemQuality.MASTER;
  }
}
